Django ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ๋ํ ํฌ๊ด์ ์ธ ๊ฐ์ด๋๋ก, ๊ตฌ์ฑ, ๊ตฌํ ๋ฐ ๋ฉํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์ ์ ๊ด๋ฆฌํ๊ธฐ ์ํ ๊ณ ๊ธ ๊ธฐ์ ์ ๋ค๋ฃน๋๋ค.
Django ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ : ๋ฉํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์ฑ ๋ง์คํฐํ๊ธฐ
๊ฐ๋ ฅํ Python ์น ํ๋ ์์ํฌ์ธ Django๋ ๋จ์ผ ํ๋ก์ ํธ ๋ด์์ ์ฌ๋ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ์ ์ฐํ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ด๋ผ๊ณ ํ๋ ์ด ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด ๋ค์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ (์ฝ๊ธฐ, ์ฐ๊ธฐ, ๋ง์ด๊ทธ๋ ์ด์ )์ ํน์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ์ง์ ํ์ฌ ๋ฐ์ดํฐ ๋ถ๋ฆฌ, ์ค๋ฉ ๋ฐ ์ฝ๊ธฐ ๋ณต์ ๋ณธ ๊ตฌํ์ ์ํ ์ ๊ตํ ์ํคํ ์ฒ๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค. ์ด ํฌ๊ด์ ์ธ ๊ฐ์ด๋๋ Django ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ๋ณต์ก์ฑ์ ์์ธํ ์ดํด๋ณด๊ณ ๊ธฐ๋ณธ ๊ตฌ์ฑ์์ ๊ณ ๊ธ ๊ธฐ์ ๊น์ง ๋ชจ๋ ๊ฒ์ ๋ค๋ฃฐ ๊ฒ์ ๋๋ค.
๋ฉํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์ฑ์ ์ฌ์ฉํ๋ ์ด์ ๋ ๋ฌด์์ ๋๊น?
๊ธฐ์ ์ ์ธ ์ธ๋ถ ์ฌํญ์ ์ดํด๋ณด๊ธฐ ์ ์ ๋ฉํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์ ์ ์ฌ์ฉํ๋ ๋๊ธฐ๋ฅผ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ด ๋งค์ฐ ์ ์ฉํ ๋ช ๊ฐ์ง ์ผ๋ฐ์ ์ธ ์๋๋ฆฌ์ค๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๋ฐ์ดํฐ ๋ถ๋ฆฌ: ๊ธฐ๋ฅ ๋๋ ๋ถ์๋ณ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฆฌํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ฌ์ฉ์ ํ๋กํ์ ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๊ณ ๊ธ์ต ๊ฑฐ๋๋ฅผ ๋ค๋ฅธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ ์ ์์ต๋๋ค. ์ด๋ ๋ณด์์ ๊ฐํํ๊ณ ๋ฐ์ดํฐ ๊ด๋ฆฌ๋ฅผ ๋จ์ํํฉ๋๋ค. ๊ธ๋ก๋ฒ ์ ์ ์๊ฑฐ๋ ํ๋ซํผ์ ์์ํด๋ณด์ธ์. ๊ณ ๊ฐ ๋ฐ์ดํฐ (์ด๋ฆ, ์ฃผ์)๋ฅผ ๊ฑฐ๋ ๋ฐ์ดํฐ (์ฃผ๋ฌธ ๋ด์ญ, ๊ฒฐ์ ์ธ๋ถ ์ ๋ณด)์์ ๋ถ๋ฆฌํ๋ฉด ๋ฏผ๊ฐํ ๊ธ์ต ์ ๋ณด๋ฅผ ์ถ๊ฐ์ ์ผ๋ก ๋ณดํธํ ์ ์์ต๋๋ค.
- ์ค๋ฉ: ์ฑ๋ฅ๊ณผ ํ์ฅ์ฑ์ ํฅ์์ํค๊ธฐ ์ํด ์ฌ๋ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ฐ์ํต๋๋ค. ์๋ฐฑ๋ง ๋ช ์ ์ฌ์ฉ์๊ฐ ์๋ ์์ ๋ฏธ๋์ด ํ๋ซํผ์ ์๊ฐํด ๋ณด์ธ์. ์ง๋ฆฌ์ ์ง์ญ (์: ๋ถ๋ฏธ, ์ ๋ฝ, ์์์)์ ๋ฐ๋ผ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ์ค๋ฉํ๋ฉด ๊ฐ๋ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํ ๋ฐ์ดํฐ ์ ๊ทผ ์๋๊ฐ ๋นจ๋ผ์ง๊ณ ๋ก๋๊ฐ ์ค์ด๋ญ๋๋ค.
- ์ฝ๊ธฐ ๋ณต์ ๋ณธ: ๊ธฐ๋ณธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฝ๊ธฐ ์ ์ฉ ๋ณต์ ๋ณธ์ผ๋ก ์ฝ๊ธฐ ์์ ์ ์คํ๋ก๋ํ์ฌ ๊ธฐ๋ณธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ก๋๋ฅผ ์ค์ ๋๋ค. ์ด๋ ์ฝ๊ธฐ๊ฐ ๋ง์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํนํ ์ ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ด์ค ์น์ฌ์ดํธ๋ ์๋ณด ์ด๋ฒคํธ ์ค์ ๋์ ํธ๋ํฝ ๋ณผ๋ฅจ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฌ๋ฌ ์ฝ๊ธฐ ๋ณต์ ๋ณธ์ ์ฌ์ฉํ๋ ๋ฐ๋ฉด, ๊ธฐ๋ณธ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์ฝํ ์ธ ์ ๋ฐ์ดํธ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ๋ ๊ฑฐ์ ์์คํ ํตํฉ: ์กฐ์ง ๋ด์ ์ด๋ฏธ ์กด์ฌํ ์ ์๋ ๋ค๋ฅธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์คํ (์: PostgreSQL, MySQL, Oracle)์ ์ฐ๊ฒฐํฉ๋๋ค. ๋ง์ ๋๊ธฐ์ ์์๋ ์ด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ธฐ์ ์ ์ฌ์ฉํ๋ ๋ ๊ฑฐ์ ์์คํ ์ ์ฌ์ฉํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ์ฌ์ฉํ๋ฉด Django ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ์ฒด ๋ง์ด๊ทธ๋ ์ด์ ์์ด ์ด๋ฌํ ์์คํ ๊ณผ ์ํธ ์์ฉํ ์ ์์ต๋๋ค.
- A/B ํ ์คํ : ํ๋ก๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํฅ์ ์ฃผ์ง ์๊ณ ์๋ก ๋ค๋ฅธ ๋ฐ์ดํฐ ์ธํธ์์ A/B ํ ์คํธ๋ฅผ ์คํํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์จ๋ผ์ธ ๋ง์ผํ ํ์ฌ๋ ์๋ก ๋ค๋ฅธ ๊ด๊ณ ์บ ํ์ธ ๋ฐ ๋๋ฉ ํ์ด์ง ๋์์ธ์ ์ฑ๊ณผ๋ฅผ ์ถ์ ํ๊ธฐ ์ํด ๋ณ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ: ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์ ๊ฐ ์๋น์ค๋ ์์ฒด ์ ์ฉ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ฐ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. Django ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ์ด๋ฌํ ์๋น์ค์ ํตํฉ์ ์ฉ์ดํ๊ฒ ํฉ๋๋ค.
Django์์ ์ฌ๋ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์ฑ
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ๊ตฌํํ๋ ์ฒซ ๋ฒ์งธ ๋จ๊ณ๋ `settings.py` ํ์ผ์์ `DATABASES` ์ค์ ์ ๊ตฌ์ฑํ๋ ๊ฒ์ ๋๋ค. ์ด ์ฌ์ ์ ๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํ ์ฐ๊ฒฐ ๋งค๊ฐ๋ณ์๋ฅผ ์ ์ํฉ๋๋ค.
```python DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'mydatabase', 'USER': 'mydatabaseuser', 'PASSWORD': 'mypassword', 'HOST': '127.0.0.1', 'PORT': '5432', }, 'users': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'user_database', 'USER': 'user_db_user', 'PASSWORD': 'user_db_password', 'HOST': 'db.example.com', 'PORT': '3306', }, 'analytics': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': 'analytics.db', }, } ```์ด ์์ ์์๋ ์ธ ๊ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ ์ํ์ต๋๋ค: `default` (PostgreSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค), `users` (MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค) ๋ฐ `analytics` (SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค). `ENGINE` ์ค์ ์ ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐฑ์๋๋ฅผ ์ง์ ํ๊ณ , ๋ค๋ฅธ ์ค์ ์ ํ์ํ ์ฐ๊ฒฐ ์ธ๋ถ ์ ๋ณด๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ฌํ ์ค์ ์ ๊ตฌ์ฑํ๊ธฐ ์ ์ ์ ์ ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๋ผ์ด๋ฒ (์: PostgreSQL์ ๊ฒฝ์ฐ `psycopg2`, MySQL์ ๊ฒฝ์ฐ `mysqlclient`)๋ฅผ ์ค์นํ๋ ๊ฒ์ ์์ง ๋ง์ธ์.
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํฐ ๋ง๋ค๊ธฐ
Django ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ํต์ฌ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํฐ ํด๋์ค๋ฅผ ๋ง๋๋ ๊ฒ์ ๋๋ค. ์ด๋ฌํ ํด๋์ค๋ ํน์ ๋ชจ๋ธ ์์ ์ ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ฒฐ์ ํ๊ธฐ ์ํ ๊ท์น์ ์ ์ํฉ๋๋ค. ๋ผ์ฐํฐ ํด๋์ค๋ ๋ค์ ๋ฉ์๋ ์ค ํ๋ ์ด์์ ๊ตฌํํด์ผ ํฉ๋๋ค.
- `db_for_read(model, **hints)`: ์ฃผ์ด์ง ๋ชจ๋ธ์ ๋ํ ์ฝ๊ธฐ ์์ ์ ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ณ์นญ์ ๋ฐํํฉ๋๋ค.
- `db_for_write(model, **hints)`: ์ฃผ์ด์ง ๋ชจ๋ธ์ ๋ํ ์ฐ๊ธฐ ์์ (์์ฑ, ์ ๋ฐ์ดํธ, ์ญ์ )์ ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ณ์นญ์ ๋ฐํํฉ๋๋ค.
- `allow_relation(obj1, obj2, **hints)`: `obj1`๊ณผ `obj2` ๊ฐ์ ๊ด๊ณ๊ฐ ํ์ฉ๋๋ฉด `True`๋ฅผ ๋ฐํํ๊ณ , ํ์ฉ๋์ง ์์ผ๋ฉด `False`๋ฅผ ๋ฐํํ๋ฉฐ, ์๊ฒฌ์ด ์์ผ๋ฉด `None`์ ๋ฐํํฉ๋๋ค.
- `allow_migrate(db, app_label, model_name=None, **hints)`: ๋ง์ด๊ทธ๋ ์ด์ ์ ์ง์ ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฉํด์ผ ํ๋ฉด `True`๋ฅผ ๋ฐํํ๊ณ , ๊ฑด๋๋ฐ์ด์ผ ํ๋ฉด `False`๋ฅผ ๋ฐํํ๋ฉฐ, ์๊ฒฌ์ด ์์ผ๋ฉด `None`์ ๋ฐํํฉ๋๋ค.
`users` ์ฑ์ ๋ชจ๋ธ์ ๋ํ ๋ชจ๋ ์์ ์ `users` ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ์ง์ ํ๋ ๊ฐ๋จํ ๋ผ์ฐํฐ๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
```python # routers.py class UserRouter: """ users ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ชจ๋ธ์ ๋ํ ๋ชจ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ์ ์ดํ๋ ๋ผ์ฐํฐ์ ๋๋ค. """ route_app_labels = {'users'} def db_for_read(self, model, **hints): """ users ๋ชจ๋ธ์ ์ฝ์ผ๋ ค๋ ์๋๋ users_db๋ก ์ด๋ํฉ๋๋ค. """ if model._meta.app_label in self.route_app_labels: return 'users' return None def db_for_write(self, model, **hints): """ users ๋ชจ๋ธ์ ์ฐ๋ ค๋ ์๋๋ users_db๋ก ์ด๋ํฉ๋๋ค. """ if model._meta.app_label in self.route_app_labels: return 'users' return 'default' def allow_relation(self, obj1, obj2, **hints): """ users ์ฑ์ ๋ชจ๋ธ์ด ๊ด๋ จ๋ ๊ฒฝ์ฐ ๊ด๊ณ๋ฅผ ํ์ฉํฉ๋๋ค. """ if ( obj1._meta.app_label in self.route_app_labels or obj2._meta.app_label in self.route_app_labels ): return True return None def allow_migrate(self, db, app_label, model_name=None, **hints): """ users ์ฑ์ด 'users' ๋ฐ์ดํฐ๋ฒ ์ด์ค์๋ง ๋ํ๋๋์ง ํ์ธํฉ๋๋ค. """ if app_label in self.route_app_labels: return db == 'users' return True ```์ด ๋ผ์ฐํฐ๋ ๋ชจ๋ธ์ ์ฑ ๋ ์ด๋ธ์ด `route_app_labels`์ ์๋์ง ํ์ธํฉ๋๋ค. ์๋ ๊ฒฝ์ฐ ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ ์์ ์ ๋ํด `users` ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ณ์นญ์ ๋ฐํํฉ๋๋ค. `allow_relation` ๋ฉ์๋๋ `users` ์ฑ์ ๋ชจ๋ธ์ด ๊ด๋ จ๋ ๊ฒฝ์ฐ ๊ด๊ณ๋ฅผ ํ์ฉํฉ๋๋ค. `allow_migrate` ๋ฉ์๋๋ `users` ์ฑ์ ๋ํ ๋ง์ด๊ทธ๋ ์ด์ ์ด `users` ๋ฐ์ดํฐ๋ฒ ์ด์ค์๋ง ์ ์ฉ๋๋๋ก ํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ถ์ผ์น๋ฅผ ๋ฐฉ์งํ๋ ค๋ฉด `allow_migrate`๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
๋ผ์ฐํฐ ํ์ฑํ
๋ผ์ฐํฐ๋ฅผ ํ์ฑํํ๋ ค๋ฉด `settings.py` ํ์ผ์ `DATABASE_ROUTERS` ์ค์ ์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
```python DATABASE_ROUTERS = ['your_project.routers.UserRouter'] ````your_project.routers.UserRouter`๋ฅผ ๋ผ์ฐํฐ ํด๋์ค์ ์ค์ ๊ฒฝ๋ก๋ก ๋ฐ๊พธ์ญ์์ค. ์ด ๋ชฉ๋ก์์ ๋ผ์ฐํฐ์ ์์๋ ์ค์ํฉ๋๋ค. Django๋ `None`์ด ์๋ ๊ฐ์ ๋ฐํํ ๋๊น์ง ๋ฐ๋ณตํฉ๋๋ค. ๋ผ์ฐํฐ๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ณ์นญ์ ๋ฐํํ์ง ์์ผ๋ฉด Django๋ `default` ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๊ณ ๊ธ ๋ผ์ฐํ ๊ธฐ์
์ด์ ์์ ์์๋ ์ฑ ๋ ์ด๋ธ์ ๊ธฐ๋ฐ์ผ๋ก ๋ผ์ฐํ ํ๋ ๊ฐ๋จํ ๋ผ์ฐํฐ๋ฅผ ๋ณด์ฌ์ฃผ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ค์ํ ๊ธฐ์ค์ ๊ธฐ๋ฐ์ผ๋ก ๋์ฑ ์ ๊ตํ ๋ผ์ฐํฐ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
๋ชจ๋ธ ํด๋์ค ๊ธฐ๋ฐ ๋ผ์ฐํ
๋ชจ๋ธ ํด๋์ค ์์ฒด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ผ์ฐํ ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ํน์ ๋ชจ๋ธ์ ๋ํ ๋ชจ๋ ์ฝ๊ธฐ ์์ ์ ์ฝ๊ธฐ ๋ณต์ ๋ณธ์ผ๋ก ๋ผ์ฐํ ํ ์ ์์ต๋๋ค.
```python class ReadReplicaRouter: """ ํน์ ๋ชจ๋ธ์ ๋ํ ์ฝ๊ธฐ ์์ ์ ์ฝ๊ธฐ ๋ณต์ ๋ณธ์ผ๋ก ๋ผ์ฐํ ํฉ๋๋ค. """ read_replica_models = ['myapp.MyModel', 'anotherapp.AnotherModel'] def db_for_read(self, model, **hints): if f'{model._meta.app_label}.{model._meta.model_name.capitalize()}' in self.read_replica_models: return 'read_replica' return None def db_for_write(self, model, **hints): return 'default' def allow_relation(self, obj1, obj2, **hints): return True def allow_migrate(self, db, app_label, model_name=None, **hints): return True ```์ด ๋ผ์ฐํฐ๋ ๋ชจ๋ธ์ ์ ๊ทํ๋ ์ด๋ฆ์ด `read_replica_models`์ ์๋์ง ํ์ธํฉ๋๋ค. ์๋ ๊ฒฝ์ฐ ์ฝ๊ธฐ ์์ ์ ๋ํด `read_replica` ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ณ์นญ์ ๋ฐํํฉ๋๋ค. ๋ชจ๋ ์ฐ๊ธฐ ์์ ์ `default` ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ์ง์ ๋ฉ๋๋ค.
ํํธ ์ฌ์ฉ
Django๋ ๋ผ์ฐํฐ์ ์ถ๊ฐ ์ ๋ณด๋ฅผ ์ ๋ฌํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ `hints` ์ฌ์ ์ ์ ๊ณตํฉ๋๋ค. ๋ฐํ์ ์กฐ๊ฑด์ ๋ฐ๋ผ ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋์ ์ผ๋ก ๊ฒฐ์ ํ๊ธฐ ์ํด ํํธ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
```python # views.py from django.db import connections from myapp.models import MyModel def my_view(request): # 'users' ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๊ฐ์ ๋ก ์ฝ๊ธฐ instance = MyModel.objects.using('users').get(pk=1) # 'analytics' ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ์ฌ ์ ๊ฐ์ฒด ๋ง๋ค๊ธฐ new_instance = MyModel(name='New Object') new_instance.save(using='analytics') return HttpResponse("Success!") ````using()` ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ํน์ ์ฟผ๋ฆฌ ๋๋ ์์ ์ ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋ผ์ฐํฐ๋ `hints` ์ฌ์ ์ ํตํด ์ด ์ ๋ณด์ ์ก์ธ์คํ ์ ์์ต๋๋ค.
์ฌ์ฉ์ ์ ํ ๊ธฐ๋ฐ ๋ผ์ฐํ
์๋ก ๋ค๋ฅธ ์ฌ์ฉ์ ์ ํ (์: ๊ด๋ฆฌ์, ์ผ๋ฐ ์ฌ์ฉ์)์ ๋ํ ๋ฐ์ดํฐ๋ฅผ ๋ณ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๋ ค๋ ์๋๋ฆฌ์ค๋ฅผ ์์ํด ๋ณด์ธ์. ์ฌ์ฉ์์ ์ ํ์ ํ์ธํ๊ณ ๊ทธ์ ๋ฐ๋ผ ๋ผ์ฐํ ํ๋ ๋ผ์ฐํฐ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
```python # routers.py from django.contrib.auth import get_user_model class UserTypeRouter: """ ์ฌ์ฉ์ ์ ํ์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ๋ผ์ฐํ ํฉ๋๋ค. """ def db_for_read(self, model, **hints): user = hints.get('instance') # ์ฌ์ฉ์ ์ธ์คํด์ค ์ถ์ถ ์๋ if user and user.is_superuser: return 'admin_db' return 'default' def db_for_write(self, model, **hints): user = hints.get('instance') # ์ฌ์ฉ์ ์ธ์คํด์ค ์ถ์ถ ์๋ if user and user.is_superuser: return 'admin_db' return 'default' def allow_relation(self, obj1, obj2, **hints): return True def allow_migrate(self, db, app_label, model_name=None, **hints): return True ```์ด ๋ผ์ฐํฐ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ์ํํ ๋ ์ฌ์ฉ์ ์ธ์คํด์ค๋ฅผ ํํธ๋ก ์ ๋ฌํด์ผ ํฉ๋๋ค.
```python # views.py from myapp.models import MyModel def my_view(request): user = request.user instance = MyModel.objects.using('default').get(pk=1) # ์ ์ฅํ๋ ๋์ ์ฌ์ฉ์ ์ธ์คํด์ค๋ฅผ ํํธ๋ก ์ ๋ฌ new_instance = MyModel(name='New Object') new_instance.save(using='default', update_fields=['name'], instance=user) # ์ฌ์ฉ์ ์ธ์คํด์ค๋ก ์ ๋ฌ return HttpResponse("Success!") ```์ด๋ ๊ฒ ํ๋ฉด ๊ด๋ฆฌ์ ์ฌ์ฉ์์ ๊ด๋ จ๋ ์์ ์ `admin_db` ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก, ์ผ๋ฐ ์ฌ์ฉ์์ ๊ด๋ จ๋ ์์ ์ `default` ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ๋ผ์ฐํ ๋ฉ๋๋ค.
๋ง์ด๊ทธ๋ ์ด์ ๊ณ ๋ ค ์ฌํญ
๋ฉํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ๊ฒฝ์์ ๋ง์ด๊ทธ๋ ์ด์ ์ ๊ด๋ฆฌํ๋ ค๋ฉด ์ฃผ์๊ฐ ํ์ํฉ๋๋ค. ๋ผ์ฐํฐ์ `allow_migrate` ๋ฉ์๋๋ ๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฉ๋๋ ๋ง์ด๊ทธ๋ ์ด์ ์ ๊ฒฐ์ ํ๋ ๋ฐ ์ค์ํ ์ญํ ์ ํฉ๋๋ค. ์ด ๋ฉ์๋๋ฅผ ์ดํดํ๊ณ ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๋ ๊ฒ์ด ํ์์ ์ ๋๋ค.
๋ง์ด๊ทธ๋ ์ด์ ์ ์คํํ ๋ `--database` ์ต์ ์ ์ฌ์ฉํ์ฌ ๋ง์ด๊ทธ๋ ์ด์ ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค.
```bash python manage.py migrate --database=users ```์ด๋ ๊ฒ ํ๋ฉด `users` ๋ฐ์ดํฐ๋ฒ ์ด์ค์๋ง ๋ง์ด๊ทธ๋ ์ด์ ์ด ์ ์ฉ๋ฉ๋๋ค. ์คํค๋ง๊ฐ ๋ชจ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ผ๊ด์ฑ์ ์ ์งํ๋๋ก ๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํด ๋ณ๋๋ก ๋ง์ด๊ทธ๋ ์ด์ ์ ์คํํด์ผ ํฉ๋๋ค.
๋ฉํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์ฑ ํ ์คํธ
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ๊ตฌ์ฑ์ด ์์๋๋ก ์๋ํ๋์ง ํ์ธํ๋ ค๋ฉด ํ ์คํธํ๋ ๊ฒ์ด ํ์์ ์ ๋๋ค. Django์ ํ ์คํธ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๊ฐ ์ฌ๋ฐ๋ฅธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ธฐ๋ก๋๊ณ ์๋์ง ํ์ธํ๋ ๋จ์ ํ ์คํธ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
```python # tests.py from django.test import TestCase from myapp.models import MyModel from django.db import connections class DatabaseRoutingTest(TestCase): def test_data_is_written_to_correct_database(self): # ๊ฐ์ฒด ์์ฑ instance = MyModel.objects.create(name='Test Object') # ๊ฐ์ฒด๊ฐ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ์ธ db = connections[instance._state.db] self.assertEqual(instance._state.db, 'default') # ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก 'default'๋ฅผ ๋ฐ๊พธ์ญ์์ค. # ํน์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๊ฐ์ฒด ๊ฒ์ instance_from_other_db = MyModel.objects.using('users').get(pk=instance.pk) # ์ค๋ฅ๊ฐ ์๊ณ ๋ชจ๋ ๊ฒ์ด ์์๋๋ก ์๋ํ๋์ง ํ์ธ self.assertEqual(instance_from_other_db.name, "Test Object") ```์ด ํ ์คํธ ์ฌ๋ก๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋์๋์ง ํ์ธํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ๊ตฌ์ฑ์ ์ฝ๊ธฐ ์์ ๋ฐ ๊ธฐํ ์ธก๋ฉด์ ํ์ธํ๋ ์ ์ฌํ ํ ์คํธ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
์ฑ๋ฅ ์ต์ ํ
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ์ ์ฐ์ฑ์ ์ ๊ณตํ์ง๋ง ์ฑ๋ฅ์ ๋ฏธ์น๋ ์ ์ฌ์ ์ํฅ์ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ฉํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ๊ฒฝ์์ ์ฑ๋ฅ์ ์ต์ ํํ๊ธฐ ์ํ ๋ช ๊ฐ์ง ํ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ ์กฐ์ธ ์ต์ํ: ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ ์กฐ์ธ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ์กํด์ผ ํ๋ฏ๋ก ๋น์ฉ์ด ๋ง์ด ๋ค ์ ์์ต๋๋ค. ๊ฐ๋ฅํ ๊ฒฝ์ฐ ํผํ์ญ์์ค.
- ์บ์ฑ ์ฌ์ฉ: ์บ์ฑ์ ์์ฃผ ์ก์ธ์คํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ก๋๋ฅผ ์ค์ด๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
- ์ฟผ๋ฆฌ ์ต์ ํ: ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฝ์ด์ผ ํ๋ ๋ฐ์ดํฐ ์์ ์ต์ํํ๊ธฐ ์ํด ์ฟผ๋ฆฌ๊ฐ ์ ์ต์ ํ๋์๋์ง ํ์ธํ์ญ์์ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง: ๋ณ๋ชฉ ํ์ ๋ฐ ๊ฐ์ ์์ญ์ ์๋ณํ๊ธฐ ์ํด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฑ๋ฅ์ ์ ๊ธฐ์ ์ผ๋ก ๋ชจ๋ํฐ๋งํฉ๋๋ค. Prometheus ๋ฐ Grafana์ ๊ฐ์ ๋๊ตฌ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฑ๋ฅ ์งํ์ ๋ํ ๊ท์คํ ํต์ฐฐ๋ ฅ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
- ์ฐ๊ฒฐ ํ๋ง: ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ค์ ํ๋ ์ค๋ฒํค๋๋ฅผ ์ค์ด๋ ค๋ฉด ์ฐ๊ฒฐ ํ๋ง์ ์ฌ์ฉํ์ญ์์ค. Django๋ ์๋์ผ๋ก ์ฐ๊ฒฐ ํ๋ง์ ์ฌ์ฉํฉ๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
Django์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ๊ตฌํํ ๋ ๋ฐ๋ผ์ผ ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๋ผ์ฐํฐ ๋จ์ํ๊ฒ ์ ์ง: ๋ผ์ฐํฐ์ ๋ณต์กํ ๋ก์ง์ ํผํ์ญ์์ค. ๊ทธ๋ฌ๋ฉด ์ ์ง ๊ด๋ฆฌ ๋ฐ ๋๋ฒ๊น ์ด ์ด๋ ค์์ง ์ ์์ต๋๋ค. ๋จ์ํ๊ณ ์ ์ ์๋ ๋ผ์ฐํ ๊ท์น์ ์ดํดํ๊ณ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ๊ฐ ๋ ์ฝ์ต๋๋ค.
- ๊ตฌ์ฑ ๋ฌธ์ํ: ๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ชฉ์ ๊ณผ ์ ์ฉ๋ ๋ผ์ฐํ ๊ท์น์ ํฌํจํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ๊ตฌ์ฑ์ ๋ช ํํ๊ฒ ๋ฌธ์ํํฉ๋๋ค.
- ์ฒ ์ ํ ํ ์คํธ: ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ๊ตฌ์ฑ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ๊ธฐ ์ํด ํฌ๊ด์ ์ธ ํ ์คํธ๋ฅผ ์์ฑํฉ๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ผ๊ด์ฑ ๊ณ ๋ ค: ์ฌ๋ฌ ์ฐ๊ธฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฒ๋ฆฌํ ๋ ํนํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ผ๊ด์ฑ์ ์ผ๋์ ๋์ญ์์ค. ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ์ ์งํ๋ ค๋ฉด ๋ถ์ฐ ํธ๋์ญ์ ๋๋ ์ต์ข ์ผ๊ด์ฑ๊ณผ ๊ฐ์ ๊ธฐ์ ์ด ํ์ํ ์ ์์ต๋๋ค.
- ํ์ฅ์ฑ์ ๊ณํํฉ๋๋ค: ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฑ์ฅํจ์ ๋ฐ๋ผ ๊ตฌ์ฑ์ ๋ณ๊ฒฝํด์ผ ํ๋ ๋ฐฉ์์ ๊ณ ๋ คํ์ฌ ํ์ฅ์ฑ์ ์ผ๋์ ๋๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ๊ตฌ์ฑ์ ์ค๊ณํฉ๋๋ค.
Django ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ๋์
Django์ ๋ด์ฅ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ๊ฐ๋ ฅํ์ง๋ง, ๋์์ ์ธ ์ ๊ทผ ๋ฐฉ์์ด ๋ ์ ์ ํ ์ํฉ์ด ์์ต๋๋ค. ๊ณ ๋ คํด์ผ ํ ๋ช ๊ฐ์ง ๋์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ทฐ: ์ฝ๊ธฐ ์ ์ฉ ์๋๋ฆฌ์ค์ ๊ฒฝ์ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ทฐ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ค ๋ผ์ฐํ ์์ด ์ฌ๋ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ์ ์ก์ธ์คํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
- ๋ฐ์ดํฐ ์จ์ดํ์ฐ์ง: ๋ณด๊ณ ๋ฐ ๋ถ์์ ์ํด ์ฌ๋ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ๋ฅผ ๊ฒฐํฉํด์ผ ํ๋ ๊ฒฝ์ฐ ๋ฐ์ดํฐ ์จ์ดํ์ฐ์ค ์๋ฃจ์ ์ด ๋ ์ ํฉํ ์ ์์ต๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค-์๋น์คํ(DBaaS): ํด๋ผ์ฐ๋ ๊ธฐ๋ฐ DBaaS ๊ณต๊ธ์๋ ์๋ ์ค๋ฉ ๋ฐ ์ฝ๊ธฐ ๋ณต์ ๋ณธ ๊ด๋ฆฌ์ ๊ฐ์ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ฌ ๋ฉํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐฐํฌ๋ฅผ ๋จ์ํํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
Django ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ฐํ ์ ๋จ์ผ ํ๋ก์ ํธ ๋ด์์ ์ฌ๋ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ด๋ฆฌํ ์ ์๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๋๋ค. ์ด ๊ฐ์ด๋์ ์ ์๋ ๊ฐ๋ ๊ณผ ๊ธฐ์ ์ ์ดํดํ๋ฉด ๋ฐ์ดํฐ ๋ถ๋ฆฌ, ์ค๋ฉ, ์ฝ๊ธฐ ๋ณต์ ๋ณธ ๋ฐ ๊ธฐํ ๊ณ ๊ธ ์๋๋ฆฌ์ค์ ๋ํด ๋ฉํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์ฑ์ ํจ๊ณผ์ ์ผ๋ก ๊ตฌํํ ์ ์์ต๋๋ค. ๊ตฌ์ฑ์ ์ ์คํ๊ฒ ๊ณํํ๊ณ , ์ฒ ์ ํ ํ ์คํธ๋ฅผ ์์ฑํ๊ณ , ์ฑ๋ฅ์ ๋ชจ๋ํฐ๋งํ์ฌ ๋ฉํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์ ์ด ์ต์ ์ผ๋ก ์๋ํ๋์ง ํ์ธํ์ญ์์ค. ์ด ๊ธฐ๋ฅ์ ๊ฐ๋ฐ์์๊ฒ ๋ณต์กํ ๋ฐ์ดํฐ ์๊ตฌ ์ฌํญ์ ์ฒ๋ฆฌํ๊ณ ์ ์ธ๊ณ์ ์ผ๋ก ๋ณํํ๋ ๋น์ฆ๋์ค ์๊ตฌ ์ฌํญ์ ์ ์ํ ์ ์๋ ํ์ฅ ๊ฐ๋ฅํ๊ณ ๊ฐ๋ ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์๋ ๋๊ตฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด ๊ธฐ์ ์ ๋ง์คํฐํ๋ ๊ฒ์ ํฌ๊ณ ๋ณต์กํ ํ๋ก์ ํธ์์ ์์ ํ๋ ๋ชจ๋ Django ๊ฐ๋ฐ์์๊ฒ ๊ท์คํ ์์ฐ์ ๋๋ค.